'use strict';

/**
 * 统计逻辑控制器
 */
const Code = require('../common/error_code');
const Cons = require('../common/constants');
const userModel = require('../models/user.model');
const ipcModel = require('../models/ipc.model');
const userRecordModel = require('../models/record_user.model');
const studentRecordModel = require('../models/record_student.model');
const strangerRecordModel = require('../models/record_stranger.model');
const Util = require('../utils/hobot_util');
const moment = require('moment');

/**
 * 人数统计
 */
async function counting(ctx) {
    const params = ctx.request.query;
    // 校验参数
    if (params.date && !Util.isDate(params.date, 'YYYYMMDD')) {
        return ctx.error(Code.RET_RECORD_STAT_ERR_PARAM);
    }

    let date = moment().format('YYYYMMDD');
    if (params.date) {
        date = Util.toISODate(params.date, 'YYYYMMDD');
    }

    // 员工总数
    const uCdt = {$or: [{u_tp: Cons.USER_TYPE_STAFF}, {u_tp: Cons.USER_TYPE_TRAINEE}]};
    const staffCnt = await userModel.find(uCdt, {u_hp: 0}).count();

    // 学生总数
    const studentCnt = await userModel.find({u_tp:Cons.USER_TYPE_STUDENT}).count();

    // 熟人记录 (关联检索效率低，废弃)
    // const match1 = {
    //     r_at: {
    //         $gte: new Date(moment(date)),
    //         $lt: new Date(moment(date).add(1, 'days'))
    //     }
    // };
    // const lookup = {
    //     from: 'user',
    //     localField: 'u_id',
    //     foreignField: '_id',
    //     as: 'user_docs'
    // };
    // const project1 = {_id: 1, u_id: 1, r_at: 1, d_id: 1, user: {$arrayElemAt: ['$user_docs', 0]}};
    // const project2 = {_id: 1, u_id: 1, r_at: 1, d_id: 1, u_nm: '$user.u_nm', u_tp: '$user.u_tp'};
    //
    // // 当日已到员工数
    // let todayStaff = 0;
    // let tmp = await userRecordModel.aggregate({$match: match1}, {$lookup: lookup}, {$project: project1},
    //     {$project: project2}, {$match: {$or: [{u_tp: Cons.USER_TYPE_STAFF}, {u_tp: Cons.USER_TYPE_TRAINEE}]}},
    //     {$group: {_id: '$u_id', total: {$sum: 1}}});
    // if (tmp) {
    //     todayStaff = tmp.length;
    // }
    //
    // // 当日访客量
    // let todayGuest = 0;
    // tmp = await userRecordModel.aggregate({$match: match1}, {$lookup: lookup}, {$project: project1},
    //     {$project: project2}, {$match: {$or: [{u_tp: Cons.USER_TYPE_GUEST}, {u_tp: Cons.USER_TYPE_VIP}]}},
    //     {$group: {_id: '$u_id', total: {$sum: 1}}});
    // if (tmp) {
    //     todayGuest = tmp.length;
    // }

    // 当日已到员工数
    let todayStaff = 0;
    let tmp = await userRecordModel.aggregate(
        {
            $match: {
                r_at: {
                    $gte: new Date(moment(date)),
                    $lt: new Date(moment(date).add(1, 'days'))
                },
                $or: [{u_tp: Cons.USER_TYPE_STAFF}, {u_tp: Cons.USER_TYPE_TRAINEE}]
            }
        },
        {$group: {_id: '$u_id', total: {$sum: 1}}},
        {$group: {_id: 1, total: {$sum: 1}}});
    if (tmp && tmp.length > 0) {
        todayStaff = tmp[0].total;
    }

    // 当日访客量
    let todayGuest = 0;
    tmp = await userRecordModel.aggregate(
        {
            $match: {
                r_at: {
                    $gte: new Date(moment(date)),
                    $lt: new Date(moment(date).add(1, 'days'))
                },
                $or: [{u_tp: Cons.USER_TYPE_GUEST}, {u_tp: Cons.USER_TYPE_VIP}]
            }
        },
        {$group: {_id: '$u_id', total: {$sum: 1}}},
        {$group: {_id: 1, total: {$sum: 1}}});
    if (tmp && tmp.length > 0) {
        todayGuest = tmp[0].total;
    }

    // 当日陌生人
    let todayStranger = 0;
    // tmp = await userRecordModel.aggregate(
    //     {
    //         $match: {
    //             r_at: {
    //                 $gte: new Date(moment(date)),
    //                 $lt: new Date(moment(date).add(1, 'days'))
    //             },
    //             u_tp: Cons.USER_TYPE_STRANGER
    //         }
    //     },
    //     {$group: {_id: '$u_id', total: {$sum: 1}}},
    //     {$group: {_id: 1, total: {$sum: 1}}});
    // if (tmp && tmp.length > 0) {
    //     todayStranger = tmp[0].total;
    // }

    todayStranger = await strangerRecordModel.find({
        r_at:{
            $gte: new Date(moment(date)),
            $lt: new Date(moment(date).add(1, 'days'))
        }
    },{r_cp:0}).count()

    // 当日人流量
    const todayTotalCdt = {
        r_at: {
            $gte: new Date(moment(date)),
            $lt: new Date(moment(date).add(1, 'days'))
        }
    };
    const cnt1 = await userRecordModel.find(todayTotalCdt, {b_qp: 0, r_cp: 0}).count();
    const todayTotal = cnt1;

    // 当日已到学生人数
    let todayStudent = 0,zeroSecondStamp = Math.floor(new Date().setHours(0,0,0,0)/1000);
    const sRecords = await studentRecordModel.find({
        c_time:{
            $gte:zeroSecondStamp,
            $lte:zeroSecondStamp+60*60*24
        }
    },'s_id s_num s_similarity c_time')
    const student_has = {}
    sRecords.forEach(item=>{
        if(!student_has[item.s_id]){
            student_has[item.s_id] = true
            todayStudent++
        }
    })
    ctx.success(Code.RET_RECORD_STAT_OK,
        {
            staff_count: staffCnt, today_staff: todayStaff,
            today_guest: todayGuest, today_stranger: todayStranger, today_total: todayTotal,
            student_count:studentCnt, today_student:todayStudent
        });
}

/**
 * 人流量统计
 */
async function traffic(ctx) {
    const params = ctx.request.query;

    // 校验参数
    if (!params.date_from || !params.date_to) {
        return ctx.error(Code.RET_STAT_TRAFFIC_ERR_PARAM);
    }
    if (!Util.isDate(params.date_from, 'YYYYMMDDHHmmss') || !Util.isDate(params.date_to, 'YYYYMMDDHHmmss')) {
        return ctx.error(Code.RET_STAT_TRAFFIC_ERR_PARAM);
    }
    let from = moment(params.date_from, 'YYYYMMDDHHmmss', true)
    let to = moment(params.date_to, 'YYYYMMDDHHmmss', true)
    if (from.isSameOrAfter(to)) {
        return ctx.error(Code.RET_STAT_TRAFFIC_ERR_TIME)
    }
    let xAxis = [];
    let size = -1;
    // 一天内则统计0-24点的分布
    if (params.date_from.substring(0, 8) === params.date_to.substring(0, 8)) {
        // 初始化坐标值
        xAxis = ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00',
            '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00',
            '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00', '23:59'];

        if (moment().format('YYYYMMDD') === params.date_to.substring(0, 8)) {
            size = parseInt(moment().format('HH')) + 2
        }
    } else {
        // 初始化坐标值
        let d = Util.toISODate(params.date_from, 'YYYYMMDDHHmmss');
        while (Util.fmtDate(d, 'YYYYMMDDHHmmss') <= params.date_to) {
            xAxis.push(Util.fmtDate(d, 'MM/DD'));
            d = d.add(1, 'days');
        }
    }

    // 以IPC区分，目前根据展示端要求是一次检索全部IPC的数据。如果IPC过多的情况，建议根据IPC筛选。
    const ipcValue = await countingByIpc(params, size);
    // 以注册用户和陌生人区分
    const userValue = await countingByStudent(params, size);

    const rst = {
        xAxis: xAxis,
        series: {
            ipc: ipcValue,
            user: userValue
        }
    };

    ctx.success(Code.RET_STAT_TRAFFIC_OK, rst);
}

/**
 * 人数统计(包含已到注册用户的ID)
 */
async function counting_detail(ctx) {
    const params = ctx.request.query;
    // 校验参数
    if (params.date && !Util.isDate(params.date, 'YYYYMMDD')) {
        return ctx.error(Code.RET_RECORD_STAT_ERR_PARAM);
    }

    let date = moment().format('YYYYMMDD');
    if (params.date) {
        date = Util.toISODate(params.date, 'YYYYMMDD');
    }

    // 员工总数
    const uCdt = {$or: [{u_tp: Cons.USER_TYPE_STAFF}, {u_tp: Cons.USER_TYPE_TRAINEE}]};
    const staffCnt = await userModel.find(uCdt, {u_hp: 0}).count();

    // 访客总数
    const gCdt = {$or: [{u_tp: Cons.USER_TYPE_GUEST}, {u_tp: Cons.USER_TYPE_VIP}]};
    const guestCnt = await userModel.find(gCdt, {u_hp: 0}).count();

    // 当日已到员工
    let todayStaff = 0;
    let todayStaffList = [];
    let tmp = await userRecordModel.aggregate(
        {
            $match: {
                r_at: {
                    $gte: new Date(moment(date)),
                    $lt: new Date(moment(date).add(1, 'days'))
                },
                $or: [{u_tp: Cons.USER_TYPE_STAFF}, {u_tp: Cons.USER_TYPE_TRAINEE}]
            }
        },
        {$group: {_id: '$u_id', total: {$sum: 1}}});
    if (tmp) {
        todayStaff = tmp.length;

        for (let item of tmp) {
            todayStaffList.push(item._id);
        }
    }

    // 当日访客量
    let todayGuest = 0;
    let todayGuestList = [];
    tmp = await userRecordModel.aggregate(
        {
            $match: {
                r_at: {
                    $gte: new Date(moment(date)),
                    $lt: new Date(moment(date).add(1, 'days'))
                },
                $or: [{u_tp: Cons.USER_TYPE_GUEST}, {u_tp: Cons.USER_TYPE_VIP}]
            }
        },
        {$group: {_id: '$u_id', total: {$sum: 1}}});
    if (tmp) {
        todayGuest = tmp.length;

        for (let item of tmp) {
            todayGuestList.push(item._id);
        }
    }

    // 当日陌生人
    let todayStranger = 0;
    tmp = await userRecordModel.aggregate(
        {
            $match: {
                r_at: {
                    $gte: new Date(moment(date)),
                    $lt: new Date(moment(date).add(1, 'days'))
                },
                $or: [{u_tp: Cons.USER_TYPE_STRANGER}]
            }
        },
        {$group: {_id: '$u_id', total: {$sum: 1}}},
        {$group: {_id: 1, total: {$sum: 1}}});
    if (tmp && tmp.length > 0) {
        todayStranger = tmp[0].total;
    }

    // 当日人流量
    const todayTotalCdt = {
        r_at: {
            $gte: new Date(moment(date)),
            $lt: new Date(moment(date).add(1, 'days'))
        }
    };
    const cnt1 = await userRecordModel.find(todayTotalCdt, {b_qp: 0, r_cp: 0}).count();
    const todayTotal = cnt1;

    ctx.success(Code.RET_RECORD_STAT_OK,
        {
            staff_count: staffCnt,
            guest_count: guestCnt,
            today_staff: todayStaff,
            today_staff_list: todayStaffList,
            today_guest: todayGuest,
            today_guest_list: todayGuestList,
            today_stranger: todayStranger,
            today_total: todayTotal
        });
}

/**
 * 以注册用户和陌生人区分统计
 * gk changed at 2018年03月22日16:23:36, 新增size参数用书数据截取
 * @param params
 * @param size
 * @returns {Promise<Array>}
 */
async function countingByUser(params, size) {
    let rst = [];

    const value = await doCounting('', params);
    if (value) {
        if (size && size > 0) {
            value.userCnt = value.userCnt.slice(0, size)
            value.strangerCnt = value.strangerCnt.slice(0, size)
            value.totalCnt = value.totalCnt.slice(0, size)
        }
        rst.push({
            name: '注册用户',
            unit: '人',
            value: value.userCnt
        });
        rst.push({
            name: '陌生人',
            unit: '人',
            value: value.strangerCnt
        });
        rst.push({
            name: '总人流量',
            unit: '人',
            value: value.totalCnt
        });
    }
    return rst;
}


/**
 * 以IPC作为区分统计
 * gk changed at 2018年03月22日16:23:29，新增size参数，用于判断数据的截取
 * @param params
 * @param size value显示的长度
 * @returns {Promise<Array>}
 */
async function countingByIpc(params, size) {
    let rst = [];

    const ipcs = await ipcModel.find({}, {_id: 1, d_nm: 1}).sort({_id: 1});
    for (let item of ipcs) {
        const value = await doCounting(item._id, params);
        if (!value) {
            continue;
        }
        if (size && size > 0) {
            value.totalCnt = value.totalCnt.slice(0, size)
        }
        rst.push({
            name: item.d_nm,
            unit: '人',
            value: value.totalCnt
        });
    }

    return rst;
}

// 学生、陌生人统计
async function countingByStudent(params, size) {
    let rst = [];
    const value = await doCounting_2(params);
    if (value) {
        if (size && size > 0) {
            value.studentCnt = value.studentCnt.slice(0, size)
            value.strangerCnt = value.strangerCnt.slice(0, size)
        }
        rst.push({
            name: '学生',
            unit: '人',
            value: value.studentCnt
        });
        rst.push({
            name: '陌生人',
            unit: '人流量',
            value: value.strangerCnt
        });
    }
    return rst;
}

async function doCounting(ipcId, params) {
    let rst = {};
    const isSameDay = params.date_from.substring(0, 8) === params.date_to.substring(0, 8);

    // 注册用户流量，陌生人流量，总人流量
    let userCnt = [], strangerCnt = [], totalCnt = [];
    let userMap, strangerMap;

    const match1 = {
        r_at: {
            $gte: new Date(Util.toISODate(params.date_from + '000', 'YYYYMMDDHHmmssSSS')),
            $lte: new Date(Util.toISODate(params.date_to + '999', 'YYYYMMDDHHmmssSSS'))
        },
        u_tp: {
            '$in': [Cons.USER_TYPE_GUEST, Cons.USER_TYPE_STAFF, Cons.USER_TYPE_TRAINEE, Cons.USER_TYPE_VIP]
        }
    };
    if (ipcId) {
        match1.d_id = ipcId;
    }
    // const project1 = {
    //     date: {$dateToString: {format: "%H:%M:%S:%L%z", date: "$r_at", timezone: "+04:30"}},
    //     u_id: "$u_id"
    // };
    let project2 = {date: {$substr: [{$add: ["$r_at", 28800000]}, 0, 10]}, u_id: "$u_id"};
    // 一天内则统计0-24点的分布
    if (isSameDay) {
        // $hour可以通过这种方式试试看
        project2 = {date: {$substr: [{$add: ["$r_at", 28800000]}, 0, 13]}, u_id: "$u_id"};

        // 初始化坐标值
        userCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        strangerCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        totalCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

    } else {
        // 初始化坐标值
        userMap = {};
        strangerMap = {};
        let d = Util.toISODate(params.date_from, 'YYYYMMDD');
        while (Util.fmtDate(d, 'YYYYMMDD') <= params.date_to) {
            const date = Util.fmtDate(d, 'YYYYMMDD');
            userMap[date] = 0;
            strangerMap[date] = 0;
            userCnt.push(0);
            strangerCnt.push(0);
            totalCnt.push(0);
            d = d.add(1, 'days');
        }
    }

    // 注册用户流量
    let temp = await userRecordModel.aggregate(
        {$match: match1},
        // {$project: project1},
        {$project: project2},
        {$group: {_id: {"date": "$date", "u_id": "$u_id"}}},
        {$group: {_id: "$_id.date", cnt: {$sum: 1}}},
        {$sort: {_id: 1}}
    );
    if (isSameDay) {
        for (let item of temp) {
            const h = Number(item._id.substring(item._id.lastIndexOf('T') + 1));
            userCnt[h + 1] = item.cnt;
        }
    } else {
        for (let item of temp) {
            const key = Util.fmtDate(item._id, 'YYYYMMDD');
            userMap[key] = item.cnt;
        }
    }

    match1.u_tp = Cons.USER_TYPE_STRANGER;
    // 陌生人流量
    project2 = {date: {$substr: [{$add: ["$r_at", 28800000]}, 0, 10]}, track_id: "$track_id"};
    if (isSameDay) {
        project2 = {date: {$substr: [{$add: ["$r_at", 28800000]}, 0, 13]}, track_id: "$track_id"};
    }
    temp = await userRecordModel.aggregate(
        {$match: match1},
        // {$project: project1},
        {$project: project2},
        {$group: {_id: "$date", cnt: {$sum: 1}}}, //因为抓拍机的track_id最多255，所以不去重
        // {$group: {_id: {"date": "$date", "track_id": "$track_id"}}}, //去重
        // {$group: {_id: "$_id.date", cnt: {$sum: 1}}},
        {$sort: {_id: 1}}
    );
    if (isSameDay) {
        for (let item of temp) {
            const h = Number(item._id.substring(item._id.lastIndexOf('T') + 1));
            strangerCnt[h + 1] = item.cnt;
        }
    } else {
        for (let item of temp) {
            const key = Util.fmtDate(item._id, 'YYYYMMDD');
            strangerMap[key] = item.cnt;
        }
    }

    // 最后数据汇总
    if (isSameDay) {
        for (let i = 0; i < userCnt.length; i++) {
            totalCnt[i] = userCnt[i] + strangerCnt[i];
        }
    } else {
        let i = 0;
        for (let key in userMap) {
            userCnt[i++] = userMap[key];
        }
        i = 0;
        for (let key in strangerMap) {
            strangerCnt[i] = strangerMap[key];
            totalCnt[i] = userCnt[i] + strangerCnt[i];
            i++;
        }
    }
    rst.userCnt = userCnt;
    rst.strangerCnt = strangerCnt;
    rst.totalCnt = totalCnt;

    return rst;
}

// 
async function doCounting_2(params) {
    let rst = {};
    const today = Number(params.date_from.substring(0, 12));
    // 学生流量，陌生人流量
    let studentCnt = [], strangerCnt = [];
    studentCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    strangerCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    const cHours = new Date().getHours();
    for(let i=0;i<=cHours;i++){
        const student_has = {};
        let student_count = 0;
        const stdRecords = await studentRecordModel.find({
            c_time:{
                $gte: Math.floor(+new Date(Util.toISODate(today+i*100+'00000', 'YYYYMMDDHHmmssSSS'))/1000),
                $lte: Math.floor(+new Date(Util.toISODate(today+(i+1)*100+'00000', 'YYYYMMDDHHmmssSSS'))/1000)
            }
        },'s_id s_num s_similarity c_time')
        stdRecords.forEach(item=>{
            if(!student_has[item.s_id]){
                student_has[item.s_id] = true
                student_count++
            }
        })
        const stgLength = await strangerRecordModel.find({
            r_at:{
                $gte: new Date(Util.toISODate(today+i*100+'00000', 'YYYYMMDDHHmmssSSS')),
                $lte: new Date(Util.toISODate(today+(i+1)*100+'00000', 'YYYYMMDDHHmmssSSS'))
            }
        },{r_cp:0}).count()
        studentCnt[i] = student_count;
        strangerCnt[i] = stgLength;
    }

    rst.studentCnt = studentCnt;
    rst.strangerCnt = strangerCnt;
    return rst;
}


// 人数统计
exports.counting = counting;
// 人流量统计
exports.traffic = traffic;

// 人数统计
exports.counting_detail = counting_detail;
